﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<iostream>
using namespace std;
// test.cpp
// 这⾥的std cout等我们都看不懂，没关系，下⾯我们会依次讲解
//#include<iostream>
//using namespace std;
//
//int main()
//{
//	cout << "hello world\n" << endl;
//	return 0;
//}


//namespace bit
//{
//	// 命名空间中可以定义变量/函数/类型
//	int rand = 10;
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//	struct Node
//	{
//		struct Node* next;
//		int val;
//	};
//}
//int main()
//{
//	printf("%d\n", rand);
//	return 0;
//}
//我们在命名空间中命名全局变量或者函数的话就不会出现冲突了
/*
但是我们现在打印这个rand显示的是这个rand是函数指针，
那么就说明这个rand是这个stdlib头文件展开的里面的rand函数

那么我们应该如何将我们命名空间中的rand的值打印出来呢？

如果我们想访问这个命名空间内的rand，那么我们需要指定一个这个空间的域
*/
//int main()
//{
//
//	printf("%p\n", rand);//00007FFB89514D50
//
//	//::域作用限定符
//	printf("%d\n", bit::rand);//10
//	//那么这里就说明我们指定要访问bit这个命名空间域里面的rand
//
//	bit::Add(1, 2);
//
//	struct bit::Node node;   
//	//我们在域作用限定符来创建结构体的时候
//	//我们需要将这个操作符放到结构体类型的名称的前面
//	return 0;
//}
/*
那么第一个打印的就是我们stdlib中展开的函数rand的地址

第二个打印的就是我们bit这个域中的rand的大小
*/

//int x = 0;//全局域
//
//namespace bit
//{
//	int x = 1;//命名空间域
//}
//
//void func()
//{
//	int x = 2;//局部域
//}
//int main()
//{
//	int x = 3;//局部域
//	printf("%d\n", x);//这里默认访问的是局部的这个x，因为搜索是先局部再全局搜索，不会到命名空间域和函数域中进行搜索的
//	
//	printf("%d\n", bit::x);//指定一下命名空间就行了
//
//	printf("%d\n", ::x);//这么就是访问全局变量，左边是空的
//	return 0;
//}
//局部域是会影响生命周期的，出了作用域就会被销毁了

//我们是不能访问func这个函数内的局部域的，局部域只能在当前这个域内进行访问的

//那么我们可以访问自己局部的，可以访问全局的，可以访问命名空间内的

//命名空间主要是与全局进行隔离，因为局部域一开始就是被隔离的

//// 命名空间可以嵌套
//namespace bit
//{
//	// 鹏哥
//	namespace pg
//	{
//		int rand = 1;
//		int Add(int left, int right)
//		{
//			return left + right;
//		}
//	}
//	// 杭哥
//	namespace hg
//	{
//		int rand = 2;
//		int Add(int left, int right)
//		{
//			return (left + right) * 10;
//		}
//	}
//}
//
//int main()
//{
//	printf("%d\n", bit::pg::rand);
//	printf("%d\n", bit::hg::rand);
//	printf("%d\n", bit::pg::Add(1, 2));
//	printf("%d\n", bit::hg::Add(1, 2));
//	return 0;
//}

//namespace bit
//{
//	int a = 0;
//	int b = 10;
//}
//
//
////using namespace bit;//暴露这个命名空间内的所有东西
//
//using bit::a;//将指定的变量展露出来，相当于这里将a暴露到全局出来了
//int b = 2;
//
//int main()
//{
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//
//	
//	bit::b++;
//	printf("%d\n", bit::b);//11   命名空间里面的
//
//	printf("%d\n", b);//2   全局的
//
//	return 0;
//}
///*
//在这里我们将a暴露出来，b就正常的方法进行使用，b不暴露
//
//*/

//using namespace std;//加上这个我们下面就可以不用指定了
////就是下面的输入和输出的话我们是不用在前面加std::的
//using std::cout;//仅仅值展开一些
//using std::endl;
//
//int main()
//{
//	//  <<这个运算符叫做流插入---输出
//	//std::cout << "hello world\n";//可以输出任意类型的变量和对象
//	cout << "hello world\n";//可以输出任意类型的变量和对象
//	//将这个字符串流向控制台---输出
//
//	int i = 10;
//	cout << i<<'\n'<<"\n";
//	//支持连续的流插入的    换行就这么写
//	double d = 1.1;
//	cout << d << endl;
//	//	std::cout << d << std::endl;
//
//	//右边的对象流向左边的控制台对象里面
//
//
//	//输入
//	//std::cin >> i >> d;//输入i  再接着输入d
//	cin >> i >> d;//输入i  再接着输入d
//
//	cout << i << ' ' << d << std::endl;  //输出i  再接着输出d  再输出换行
//
//	return 0;
//}
/*
我们这里是不需要像c语言一样要在前面定义%s %d  这些东西
*/
/*
换行的两种方法：在我们输出的后面接着输出换行'\n'或者是"\n"

另一种方法就是在后面输出std::endl
endl就是end line的缩写  结束一行

endl这个实际上是一个函数
std::endl这个的兼容性相较于'\n'的话更强一些
根据平台的不同会进行处理的 
*/

/*
输入输出的话我们用c语言的scanf和printf都是可以的
但是我们要指定类型

c++的输入和输出就不用指定类型了

C/C++是可以混在一起用的，不会有什么问题的

如果想控制打印出来的小数点的精度的话，建议使用printf
因为C++的话控制这个精度的话会很麻烦的
*/

//#include <iostream>
//#include <assert.h>
//using namespace std;
//void Func(int a = 0)
//{
//	cout << a << endl;
//}
//int main()
//{
//	Func(); // 没有传参时，使⽤参数的默认值
//	Func(10); // 传参时，使⽤指定的实参
//	return 0;
//}
////如果我们没有传参的话，我们就使用的是这个缺省值
////对于这个函数func的话，我们没有传参的话，那么我们就用函数内的缺省参数作为默认值
////如果传了参的话，我们就用传的参
//
////那么第一个函数打印的就是0
////第二个函数打印的就是10

//#include <iostream>
//using namespace std;
//// 全缺省   缺省全部参数
//void Func1(int a = 10, int b = 20, int c = 30)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//// 半缺省  缺省部分参数
//void Func2(int a, int b = 10, int c = 20)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//int main()
//{
//	Func1();//可以一个都不传，全用的就是缺省值
//	Func1(1);//仅仅传第一个给a，剩下的b和c用缺省值
//	Func1(1, 2);//传a和b，c用缺省值
//	Func1(1, 2, 3);//三个都传，那么三个都不用缺省值
//	//Func1(,2,);//这样写是错的，因为我们这么写不支持，因为我们传参要连续传参
//
//	Func2(100);
//	Func2(100, 200);	
//	Func2(100, 200, 300);
//	return 0;
//}
/*
a = 10
b = 20
c = 30

a = 1
b = 20
c = 30

a = 1
b = 2
c = 30

a = 1
b = 2
c = 3

a = 100
b = 10
c = 20

a = 100
b = 200
c = 20

a = 100
b = 200
c = 300

*/

//using namespace std;
////参数类型不同
//int Add(int left, int right)//对整数的加法
//{
//	cout << "int Add(int left, int right)" << endl;
//	return left + right;
//}
//double Add(double left, double right)//对小数的加法
//{
//	cout << "double Add(double left, double right)" << endl;
//	return left + right;
//}
//
//
//// 2、参数个数不同
//void f()
//{
//	cout << "f()" << endl;
//}
//void f(int a)
//{
//	cout << "f(int a)" << endl;
//}
//
//// 3、参数类型顺序不同
//void f(int a, char b)
//{
//	cout << "f(int a,char b)" << endl;
//}
//void f(char b, int a)
//{
//	cout << "f(char b, int a)" << endl;
//}
//
//
////语法上下面的两个函数构成重载，但是我们在调用的时候就会有歧义了
////我们不知道调用的是哪个
////语法上是可以存在的，但是在实际运用中是不能存在的
//void f1()
//{
//	cout << "f()" << endl;
//}
//void f1(int a = 10)
//{
//	cout << "f(int a)" << endl;
//}
//
//int main()
//{
//	//下面的两个函数其实是不同的函数
//	//参数的类型不同
//	Add(10, 20);
//	Add(10.1, 20.2);
//
//	//参数个数不同
//	f();
//	f(10);
//
//	//参数顺序不同  本质还是类型不同
//	f(10, 'a');
//	f('a', 10);
//	return 0;
//}
///*
//如果是返回值不同那么能不能构成重载呢？
//答案是不能的，因为光凭借这个我们是不能进行判断的
//
//但是我们的参数个数以及参数顺序和参数类型不同都能进行判断函数的不同，那么就能进行重载
//*/

//using namespace std;
//
//void Swap(int& rx, int& ry)//之前我们是没有&这个稍微，那么这里的参数就是a和b的拷贝
////因为是传值所以是不能进行根本性的交换的
////所以我们在进行交换函数的时候我们是要传地址的，使用指针的
//
////那么现在我们在函数的定义中我们直接将a的别名和b的别名定义在里面
////那么因为rx是a的别名，ry是b的别名，那么我们通过这两个别名就能访问他们的地址了
////并且我们在这个主函数里面我们在进行交换函数的时候我们是不需要进行取地址的操作的
////因为我们的函数传的参是a  那么我们为a取别名叫rx  那么rx就是a
//
////那么rx和ry的交换就是a和e的交换
//
////那么就是形参的改变就改变了实参
//{
//	int tmp = rx;
//	rx = ry;
//	ry = tmp;
//}
//int main()
//{
//	int a = 0;
//	//int b = a;//将a赋值给b
//
//	int& b = a;//给a的这块空间取别名。叫b
//	
//	int& c = a;//再给a取别名叫c
//
//	int& d = b;//也可以给b取别名
//
//	//其实就是这么一块空间有多个名字
//
//	cout << &a << endl;
//	cout << &b << endl;
//	cout << &c << endl;
//	cout << &d << endl;
//	//这四个变量的地址都是一样的
//	b++;
//	//那么我们进行b++的话，a c d 的大小都会被改变的
//
//
//	//我们还能给指针p1取别名
//	int* p1 = &a;
//	int*& p2 = p1;
//
//	int e = 10;
//	p2 = &e;//将p2改变指向从a变成e 
//	//因为p1就是p2
//	//那么随着p2的改变，那么p1也改变了
//	cout << *p1 << endl;
//
//
//
//	int x = 0, y = 1;
//	cout << x << " " << y << endl;
//	Swap(x, y);
//	cout << x << " " << y << endl;
//	return 0;
//
//	return 0;
//}

//我们这里是给变量取别名
//但是typedef是给类型取别名
//typedef int type  
// 
//define是定义宏

//&这个在c语言中是取地址的符号，但是我们在这里是引用的意思
//就是给这个变量起个小名

//引用是不能替代指针的

//typedef struct ListNode
//{
//	int val;
//	struct ListNode* next;
//}LTNode, * PNode;
//// 指针变量也可以取别名，这⾥LTNode*& phead就是给指针变量取别名
//// 这样就不需要⽤⼆级指针了，相对⽽⾔简化了程序
////void ListPushBack(LTNode** phead, int x)
////void ListPushBack(LTNode*& phead, int x)
//void ListPushBack(PNode& phead, int x)
//{
//	PNode newnode = (PNode)malloc(sizeof(LTNode));
//	newnode->val = x;
//	newnode->next = NULL;
//	if (phead == NULL)
//	{
//		phead = newnode;
//	}
//	else
//	{
//		//...
//	}
//}
//
//
//int main()
//{
//	PNode plist = NULL;
//	ListPushBack(plist, 1);   //那么我们传上去的plist的别名就是phead
//	return 0;
//}
////将plist引用一个新的名字